在一個同系列目標的操作流程中,將各個 fragment 歸類在同一個 navigation 內非常有用,可以幫助我們分類、可讀性與維護性也更高。
例如:一開啟 App 時判斷是否登入,如果沒有登入則導航至另一個登入流程的 navigation。
1.在導航編輯器中,按住Shift鍵,點擊想要歸類在同一個 navigation 的 fragment
2.右鍵 Move to Nested Graph -> New Graph
這時候就會在 navigation 底下多一層嵌套的 navigation,並指定 startDestination。
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph_main"
    app:startDestination="@id/page3Fragment">
    <navigation
        android:id="@+id/navigation_login"
        app:startDestination="@id/loginPage1Fragment">
        
        <fragment
            android:id="@+id/loginPage1Fragment"
        .
        .
        .
        </fragment>
        
        <fragment
            android:id="@+id/loginPage2Fragment"
        .
        .
        .
        </fragment>
    </navigation>
使用時把這個整包的 navigation 當成是一個 fragment 來用,切換到這個 navigation 時自然也是從他的 startDestination 當作起始頁。
    <fragment
        android:id="@+id/page3Fragment"
        android:name="com.guanhong.mvvmpractice.view.navigation.FragmentThree"
        android:label="fragment_page3"
        tools:layout="@layout/fragment_navigation_three">
        
        <action
            android:id="@+id/action_page3Fragment_to_navigation_login"
            app:destination="@id/navigation_login" />
    </fragment>
     <navigation
        android:id="@+id/navigation_login"
        app:startDestination="@id/loginPage1Fragment">
        
        <fragment
            android:id="@+id/loginPage1Fragment"
        .
        .
        .
        </fragment>
        
        <fragment
            android:id="@+id/loginPage2Fragment"
        .
        .
        .
        </fragment>
    </navigation>
    textView.setOnClickListener {
    
                     Navigation
                     .findNavController(it)
                     .navigate(R.id.action_page3Fragment_to_navigation_login)
        }
使用 navigation 要如何在 fragments 之間傳遞參數呢
之前換頁的代碼
        Navigation
        .findNavController(it)
        .navigate(R.id.action_page2_to_action_page3)
navigate 點進去看源碼,用的都是這個
    public void navigate(@IdRes int resId) {
        navigate(resId, null);
    }
往下拉會發現,這個 navigate 用多形寫了很多方法,其中一個就是可以用來丟 bundle 的方法。
    public void navigate(@IdRes int resId, @Nullable Bundle args) {
        navigate(resId, args, null);
    }
所以可以像平常丟參數的方法一樣丟 bundle 進去
        val bundle = Bundle()
        bundle.putString("userName", userName)
        Navigation
        .findNavController(it)
        .navigate(R.id.action_page2_to_action_page3, bundle)
獲得數據
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
    var userName: String? = null
     arguments?.let {
                userName = it.getString("userName")
            }
}
也可以直接在 fragment 標籤內加上 argument 標籤,就可以設定 defaultValue
    <fragment
        android:id="@+id/page1Fragment"
        android:name="com.guanhong.mvvmpractice.view.navigation.FragmentOne"
        android:label="fragment_page1"
        tools:layout="@layout/fragment_navigation_one">
        
        <action
            android:id="@+id/action_page1_to_action_page2"
            app:destination="@id/page2Fragment" />
            
        <argument
            android:name="userName"
            android:defaultValue="user name"
            app:argType="string" />
    </fragment>
這個 argument 是代表這個 fragment 會接受到的 argument,不是要傳出去的。
Navigation 算是一個相當方便的組件,能夠輕鬆的以圖像的方式處理好,fragment 之間的換頁流程,內建轉場動畫能使換頁更加流暢,切換 fragment 的動作只需要一行代碼就搞定,實在太方便啦!
唯一的缺點就是預設的切換方式是用 replace ,要換成 show、hide 的話就必需自已客製 NavController,就會比較麻煩一點。
有任何問題或講得不清楚的地方歡迎留言和我討論。
更歡迎留言糾正我任何說錯的地方!